<?php
namespace App\Admin\Controllers\Inventory;

use App\Importer\Inventory\CNImporter;
use App\Models\Basics\SysArea;
use App\Models\Inventory\Adjust;
use App\Models\Inventory\AdjustArea;
use App\Models\Inventory\InventoryCn;
use App\Models\Inventory\PublicCn;
use App\Models\Inventory\Timely;
use App\Models\Product\ProductSku;
use App\Util\RExcel;
use Encore\Admin\Controllers\AdminController;
use Encore\Admin\Facades\Admin;
use Illuminate\Database\QueryException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Maatwebsite\Excel\Facades\Excel;
use Symfony\Component\HttpFoundation\File\UploadedFile;
class AdjustUploadController extends AdminController{

    protected $title = '实时库存调整';

    protected function grid()
    {
        return view('inventory.adjust-upload.index');
    }

    public function upload(Request $request){
        $reason = $request->get('reason');
        if(!array_key_exists($reason,Adjust::$_func)){
            admin_toastr('调整原因无效','error');
            return back()->withInput();
        }
        $file = $request->file('source_file');
        if ($file->isValid()) {
            $func = Adjust::$_func[$reason];
            $re = $this->{'_import'.$func}($file);
            if(is_array($re)) {
                if($re['flag']){
                    admin_toastr('文件：'.$re['data'].' 上传成功！');
                }else{
                    admin_toastr($re['data'],'error');
                }
            }else{
                return $re;
            }
        }else{
            admin_toastr('无效文件！','error');
        }
        return back()->withInput();
    }

    private function _importCheck(UploadedFile $file){
        try{
            $data = Excel::toArray(new CNImporter(),$file);
            $data = $data[0];
            if(!$data)return ['flag' => false,'data' => '请上传包含有数据的文件！'];
            $errors = [];
            $count = 1;
            $arr = [];
            $userId = Admin::user()->id;
            foreach($data as $row){
                $count++;
                $sku = $row[0] ? trim($row[0]) : '';
                $num = $row[1] ? trim($row[1]) : 0;
                if(!$sku){
                    $errors[$count] = '必填项为空';
                    continue;
                }
                if(!in_array($sku,$arr)){
                    $arr[$count] = $sku;
                }else{
                    $errors[$count] = '重复记录';
                    continue;
                }
                if(!is_numeric($num)){
                    $errors[$count] = '数量格式有误';
                    continue;
                }
                if($num < 0){
                    $errors[$count] = '数量不能小于0';
                    continue;
                }
                $pSkuId = ProductSku::getValueByCode($sku,'id');
                if(!$pSkuId){
                    $errors[$count] = $sku.'系统不存在';
                    continue;
                }
                $timely = Timely::getInstant($pSkuId);
                if($timely == $num)continue;
                DB::beginTransaction();
                if($num == 0){
                    $inventory = InventoryCn::query()
                        ->where('instant','>',0)
                        ->where('psku_id',$pSkuId)
                        ->lockForUpdate()
                        ->get();
                    $i = 0;
                    foreach ($inventory as $_inventory){
                        $bNum = $_inventory->instant;
                        $_inventory->instant = 0;
                        $flag = $_inventory->save();
                        if(!$flag){
                            break;
                        }
                        $adjustArea = AdjustArea::query()->create(
                            [
                                'area_id' => $_inventory->area_id,
                                'psku_id' => $pSkuId,
                                'b_num' => $bNum,
                                'a_num' => 0,
                                'auser_id' => $userId
                            ]
                        );
                        if(!$adjustArea){
                            break;
                        }
                        $i++;
                    }
                    if($inventory->count() != $i){
                        DB::rollBack();
                        continue;
                    }
                }else{
                    if($timely > $num){
                        $publicCn = PublicCn::query()
                            ->whereHas('area', function ($query){
                                $query->where('area', 'PUBLIC');
                            })
                            ->where('psku_id',$pSkuId)
                            ->where('instant','>',0)
                            ->lockForUpdate()
                            ->first();
                        $_adjustNum = $timely - $num;
                        if($publicCn){
                            $tempInstant = $publicCn->instant;
                            $_canAdjustNum = min($_adjustNum,$tempInstant);
                            $publicCn->instant -= $_canAdjustNum;
                            $flag1 = $publicCn->save();
                            if(!$flag1){
                                DB::rollBack();
                                continue;
                            }
                            $adjustArea = AdjustArea::query()->create(
                                [
                                    'area_id' => $publicCn->area_id,
                                    'psku_id' => $pSkuId,
                                    'b_num' => $tempInstant,
                                    'a_num' => $publicCn->instant,
                                    'auser_id' => $userId
                                ]
                            );
                            if(!$adjustArea){
                                DB::rollBack();
                                continue;
                            }
                            $_adjustNum -= $_canAdjustNum;
                        }
                        if($_adjustNum > 0){
                            $inventory = InventoryCn::query()
                                ->where('instant','>',0)
                                ->where('psku_id',$pSkuId)
                                ->orderBy('instant','DESC')
                                ->lockForUpdate()
                                ->get();
                            $flag2 = FALSE;
                            foreach($inventory as $_inventory){
                                $tempInstant = $_inventory->instant;
                                $_canAdjustNum = min($_adjustNum,$tempInstant);
                                $_inventory->instant -= $_canAdjustNum;
                                $_flag = $_inventory->save();
                                if(!$_flag){
                                    $flag2 = FALSE;
                                    break;
                                }
                                $adjustArea = AdjustArea::query()->create(
                                    [
                                        'area_id' => $_inventory->area_id,
                                        'psku_id' => $pSkuId,
                                        'b_num' => $tempInstant,
                                        'a_num' => $_inventory->instant,
                                        'auser_id' => $userId
                                    ]
                                );
                                if(!$adjustArea){
                                    $flag2 = FALSE;
                                    break;
                                }
                                $flag2 = TRUE;
                                if($_canAdjustNum == $_adjustNum){
                                    break;
                                }else{
                                    $_adjustNum -= $_canAdjustNum;
                                }
                            }
                            if(!$flag2){
                                DB::rollBack();
                                continue;
                            }
                        }
                    }else{
                        $_adjustNum = $num - $timely;
                        $pAreaId = SysArea::getSysAreaIdByArea();
                        $publicCn = PublicCn::query()
                            ->firstOrNew([
                                'area_id' => $pAreaId,
                                'psku_id' => $pSkuId,
                            ]);
                        $tempInstant = $publicCn->instant ?: 0;
                        $publicCn->instant += $_adjustNum;
                        $flag3 = $publicCn->save();
                        if(!$flag3){
                            DB::rollBack();
                            continue;
                        }
                        $adjustArea = AdjustArea::query()->create(
                            [
                                'area_id' => $pAreaId,
                                'psku_id' => $pSkuId,
                                'b_num' => $tempInstant,
                                'a_num' => $publicCn->instant,
                                'auser_id' => $userId
                            ]
                        );
                        if(!$adjustArea){
                            DB::rollBack();
                            continue;
                        }
                    }
                }
                $adjust = Adjust::query()->create(['psku_id' => $pSkuId,'num' => $num,'reason' => 1,'auser_id' => $userId]);
                if($adjust){
                    DB::commit();
                }else{
                    $errors[$count] = $sku.'调整记录添加失败';
                    DB::rollBack();
                }
            }
            if(empty($errors)){
                return ['flag' => true,'data' => $file->getClientOriginalName()];
            }else{
                return RExcel::importResult($errors);
            }
        }catch(QueryException $qe){
            report($qe);
            return ['flag' => false,'data' => '系统异常！'];
        }catch(\Exception $e){
            report($e);
            return ['flag' => false,'data' => '系统异常！'];
        }
    }

    private function _importDiffer(UploadedFile $file){
        try{
            $data = Excel::toArray(new CNImporter(),$file);
            $data = $data[0];
            if(!$data)return ['flag' => false,'data' => '请上传包含有数据的文件！'];
            $errors = [];
            $count = 1;
            $arr = [];
            $userId = Admin::user()->id;
            foreach($data as $row){
                $count++;
                $sku = $row[0] ? trim($row[0]) : '';
                $num = $row[1] ? trim($row[1]) : 0;
                if(!$sku){
                    $errors[$count] = '必填项为空';
                    continue;
                }
                if(!in_array($sku,$arr)){
                    $arr[$count] = $sku;
                }else{
                    $errors[$count] = '重复记录';
                    continue;
                }
                if(!is_numeric($num)){
                    $errors[$count] = '数量格式有误';
                    continue;
                }
                if($num == 0){
                    $errors[$count] = '数量不能为0';
                    continue;
                }
                $pSkuId = ProductSku::getValueByCode($sku,'id');
                if(!$pSkuId){
                    $errors[$count] = $sku.'系统不存在';
                    continue;
                }
                $timely = Timely::getInstant($pSkuId);
                $aNum = $timely + $num;
                if($aNum < 0){
                    $errors[$count] = $sku.'库存不足';
                    continue;
                }
                DB::beginTransaction();
                if($num > 0){
                    $pAreaId = SysArea::getSysAreaIdByArea();
                    $publicCn = PublicCn::query()
                        ->firstOrNew([
                            'area_id' => $pAreaId,
                            'psku_id' => $pSkuId,
                        ]);
                    $tempInstant = $publicCn->instant;
                    $publicCn->instant += $num;
                    $flag1 = $publicCn->save();
                    if(!$flag1){
                        DB::rollBack();
                        continue;
                    }
                    $adjustArea = AdjustArea::query()->create(
                        [
                            'area_id' => $pAreaId,
                            'psku_id' => $pSkuId,
                            'b_num' => $tempInstant,
                            'a_num' => $publicCn->instant,
                            'auser_id' => $userId
                        ]
                    );
                    if(!$adjustArea){
                        DB::rollBack();
                        continue;
                    }
                }else{
                    $_adjustNum = abs($num);
                    $publicCn = PublicCn::query()
                        ->whereHas('area', function ($query){
                            $query->where('area', 'PUBLIC');
                        })
                        ->where('psku_id',$pSkuId)
                        ->where('instant','>',0)
                        ->lockForUpdate()
                        ->first();
                    if($publicCn){
                        $tempInstant = $publicCn->instant;
                        $_canAdjustNum = min($_adjustNum,$tempInstant);
                        $publicCn->instant -= $_canAdjustNum;
                        $flag2 = $publicCn->save();
                        if(!$flag2){
                            DB::rollBack();
                            continue;
                        }
                        $adjustArea = AdjustArea::query()->create(
                            [
                                'area_id' => $publicCn->area_id,
                                'psku_id' => $pSkuId,
                                'b_num' => $tempInstant,
                                'a_num' => $publicCn->instant,
                                'auser_id' => $userId
                            ]
                        );
                        if(!$adjustArea){
                            DB::rollBack();
                            continue;
                        }
                        $_adjustNum -= $_canAdjustNum;
                    }
                    if($_adjustNum > 0){
                        $inventory = InventoryCn::query()
                            ->where('instant','>',0)
                            ->where('psku_id',$pSkuId)
                            ->orderBy('instant','DESC')
                            ->lockForUpdate()
                            ->get();
                        $flag3 = FALSE;
                        foreach($inventory as $_inventory){
                            $tempInstant = $_inventory->instant;
                            $_canAdjustNum = min($_adjustNum,$tempInstant);
                            $_inventory->instant -= $_canAdjustNum;
                            $_flag = $_inventory->save();
                            if(!$_flag){
                                $flag3 = FALSE;
                                break;
                            }
                            $adjustArea = AdjustArea::query()->create(
                                [
                                    'area_id' => $_inventory->area_id,
                                    'psku_id' => $pSkuId,
                                    'b_num' => $tempInstant,
                                    'a_num' => $_inventory->instant,
                                    'auser_id' => $userId
                                ]
                            );
                            if(!$adjustArea){
                                $flag3 = FALSE;
                                break;
                            }
                            $flag3 = TRUE;
                            if($_canAdjustNum == $_adjustNum){
                                break;
                            }else{
                                $_adjustNum -= $_canAdjustNum;
                            }
                        }
                        if(!$flag3){
                            DB::rollBack();
                            continue;
                        }
                    }
                }
                $adjust = Adjust::query()->create(['psku_id' => $pSkuId,'num' => $num,'reason' => 2,'auser_id' => $userId]);
                if($adjust){
                    DB::commit();
                }else{
                    $errors[$count] = $sku.'调整记录添加失败';
                    DB::rollBack();
                }
            }
            if(empty($errors)){
                return ['flag' => true,'data' => $file->getClientOriginalName()];
            }else{
                return RExcel::importResult($errors);
            }
        }catch(\Exception $e){
            report($e);
            return ['flag' => false,'data' => '系统异常！'];
        }
    }

    public function template(Request $request){
        $temp = $request->get('temp');
        $suffix = $request->get('suffix','xlsx');
        return Storage::disk('admin')->download("template/{$temp}-template.{$suffix}");
    }
}
